﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Brain.Animation
{
    public class Animation<T, K> : IBaseAnimation where T : struct where K : IKeyframe<T>
    {
        public List<K> Frames;

        public bool Loop { get; set; }

        private int currentFrame;
        public int CurrentFrame
        {
            get { return currentFrame; }
            set
            {
                currentFrame = value;
                Update();
            }
        }

        public void UpdateLoop(float frameDif)
        {
        }

        public int AnimationEnd
        {
            get { return totalTime; }   
        }

        public int StartFrame { get; set; }

        protected GetGeneric<T> Get;
        protected SetGeneric<T> Set;
        public Animation(GetGeneric<T> get, SetGeneric<T> set)
        {
            this.Get = get;
            this.Set = set;

            Frames = new List<K>();
        }

        private int totalTime;
        public void SubmitFrame(T frame, int time)
        {
            if (time > totalTime)
            {
                totalTime = time;
            }
            IKeyframe<T> f = default(K);
            f.Get = Get;
            f.Set = Set;
            f.Time = time;
            f.Value = frame;
            this.Frames.Add((K)f);
        }

        private void Update()
        {
            IKeyframe<T> Frame = FindFrame(CurrentFrame);

            if (Frame != null)
            {
                this.Set(Frame.Value);
            }
            else
            {
                Frame = FindNextFrame();
                if (Frame == null)
                    return;

                IKeyframe<T> LastFramePlayed = FindLastKeyFrame(Frame);

                if (Frame != null)
                {
                    float amount = ((float)CurrentFrame - LastFramePlayed.Time) / ((float)Frame.Time - LastFramePlayed.Time);

                    this.Set(LastFramePlayed.Lerp(LastFramePlayed.Value, Frame.Value, amount));
                }
            }
        }

        public void Update(int frame)
        {
            this.CurrentFrame = frame;
        }

        protected IKeyframe<T> FindFrame(int Frame)
        {
            for (int i = 0; i < Frames.Count; i++)
            {
                if (Frames[i].Time == Frame)
                {
                    return Frames[i];
                }
            }
            return null;
        }
        protected IKeyframe<T> FindLastKeyFrame(IKeyframe<T> frame)
        {
            IKeyframe<T> lastFoundFrame = null;
            for (int i = 0; i < Frames.Count; i++)
            {
                if (lastFoundFrame == null)
                {
                    if (Frames[i].Time < frame.Time)
                        lastFoundFrame = Frames[i];
                }
                else
                {
                    if (Frames[i].Time < frame.Time &&
                        Frames[i].Time > lastFoundFrame.Time)
                        lastFoundFrame = Frames[i];
                }
            }

            return lastFoundFrame;
        }
        protected IKeyframe<T> FindNextFrame()
        {
            int MinFrame = this.CurrentFrame;
            IKeyframe<T> frameFound = null;

            for (int i = 0; i < Frames.Count; i++)
            {
                if (frameFound == null && Frames[i].Time > MinFrame)
                {
                    frameFound = Frames[i];
                }
                if (frameFound != null)
                {
                    if (Frames[i].Time > MinFrame &&
                        Frames[i].Time < frameFound.Time)
                        frameFound = Frames[i];
                }
            }

            return frameFound;
        }



    }
}
